package goloader

import (
	"arch/x86/x86asm"
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"mmap"
	"objfile/goobj"
	"os"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"unsafe"
)

func mustOK(err error) {
	if err != nil {
		panic(err)
	}
}

// copy from $GOROOT/src/cmd/internal/objabi/reloctype.go
const (
	// R_TLS_LE, used on 386, amd64, and ARM, resolves to the offset of the
	// thread-local symbol from the thread local base and is used to implement the
	// "local exec" model for tls access (r.Sym is not set on intel platforms but is
	// set to a TLS symbol -- runtime.tlsg -- in the linker when externally linking).
	R_TLS_LE    = 16
	R_CALL      = 8
	R_CALLARM   = 9
	R_CALLARM64 = 10
	R_CALLIND   = 11
	R_PCREL     = 15 // 是否为pc相对值
	R_ADDR      = 1
	// R_ADDRARM64 relocates an adrp, add pair to compute the address of the
	// referenced symbol.
	R_ADDRARM64 = 3
	// R_ADDROFF resolves to a 32-bit offset from the beginning of the section
	// holding the data being relocated to the referenced symbol.
	R_ADDROFF = 5
	// R_WEAKADDROFF resolves just like R_ADDROFF but is a weak relocation.
	// A weak relocation does not make the symbol it refers to reachable,
	// and is only honored by the linker if the symbol is in some other way
	// reachable.
	R_WEAKADDROFF = 6
	// R_METHODOFF resolves to a 32-bit offset from the beginning of the section
	// holding the data being relocated to the referenced symbol.
	// It is a variant of R_ADDROFF used when linking from the uncommonType of a
	// *rtype, and may be set to zero by the linker if it determines the method
	// text is unreachable by the linked program.
	R_METHODOFF = 24
)

// copy from $GOROOT/src/cmd/internal/objabi/symkind.go
const (
	// An otherwise invalid zero value for the type
	Sxxx = iota
	// Executable instructions
	STEXT
	// Read only static data
	SRODATA
	// Static data that does not contain any pointers
	SNOPTRDATA
	// Static data
	SDATA
	// Statically data that is initially all 0s
	SBSS
	// Statically data that is initially all 0s and does not contain pointers
	SNOPTRBSS
	// Thread-local data that is initally all 0s
	STLSBSS
	// Debugging data
	SDWARFINFO
	SDWARFRANGE
)

var (
	tmpModule   interface{}
	modules     = make(map[interface{}]bool)
	modulesLock sync.Mutex
	mov32bit    = [8]byte{0x00, 0x00, 0x80, 0xD2, 0x00, 0x00, 0xA0, 0xF2}
)

type SymData struct {
	Name   string
	Kind   int
	Offset int
	Reloc  []Reloc
}

type Reloc struct {
	Offset int
	SymOff int
	Size   int
	Type   int
	Add    int
}

// CodeReloc dispatch and load CodeReloc struct via network is OK
type CodeReloc struct {
	Code []byte
	Data []byte
	Mod  Module
	Syms []SymData
}

type itabSym struct {
	ptr   int
	inter int
	_type int
}

type itabReloc struct {
	locOff  int
	symOff  int
	size    int
	locType int
	add     int
}

type symFile struct {
	sym  *goobj.Sym
	file *os.File
}

type CodeModule struct {
	Syms       map[string]uintptr
	CodeByte   []byte
	Module     interface{}
	pcfuncdata []findfuncbucket
	stkmaps    [][]byte
	itabs      []itabReloc
	itabSyms   []itabSym
	typemap    map[typeOff]uintptr
}

// Unload 卸载库
func (cm *CodeModule) Unload() {
	runtime.GC()
	modulesLock.Lock()
	removeModule(cm.Module, runtime.Version())
	modulesLock.Unlock()
	mmap.Munmap(cm.CodeByte)
}

// Compile 反编译
func (cm *CodeModule) Compile() (Set string) {
	mode, ok := cm.Module.(*moduledata110)
	if !ok {
		return "反编译 失败"
	}
	end := int(mode.etext - mode.types)
	if end < 1 {
		return "反编译 代码区大小异常"
	}
	pc := 0
	Set = ".Code\n"
	for pc < end {
		inst, _ := x86asm.Decode(cm.CodeByte[pc:], 64)
		Set += fmt.Sprintf("0x%-10x 0x%-18X %s\n", pc, cm.CodeByte[pc:pc+inst.Len], inst.String())
		pc += inst.Len
	}
	Set += ".Data\n"
	end = len(cm.CodeByte)
	n := pc
	for {
		n = pc
		pc += 4
		if pc > end {
			Set += fmt.Sprintf("0x%-10x 0x%-16X\n", n, cm.CodeByte[n:])
			return Set
		}
		// 转地址
		Set += fmt.Sprintf("0x%-10x 0x%-16X\n", n, cm.CodeByte[n:pc])
	}
	return Set
}

// readAtSeeker 内部结构体,用于读数据
type readAtSeeker struct {
	io.ReadSeeker
}

func (r *readAtSeeker) ReadAt(p []byte, offset int64) (n int, err error) {
	_, err = r.Seek(offset, io.SeekStart)
	if err != nil {
		return
	}
	return r.Read(p)
}

// ReadObjs 加载多个动态库
// + files   文件列表
// + pkgPath 对应包目录,用于错误输出.
func ReadObjs(files []string, pkgPath []string) (*CodeReloc, error) {
	var fs []*os.File
	for _, file := range files {
		f, err := os.Open(file)
		if err != nil {
			return nil, err
		}
		fs = append(fs, f)
		defer f.Close()
	}

	var allSyms = make(map[string]symFile)

	var symMap = make(map[string]int)
	var gcObjs = make(map[string]uintptr)
	var fileTabOffsetMap = make(map[string]int)

	var reloc CodeReloc

	var goObjs []*goobj.Package
	for i, f := range fs {
		if pkgPath[i] == "" {
			pkgPath[i] = "main"
		}
		obj, err := goobj.Parse(f, pkgPath[i])
		if err != nil {
			return nil, fmt.Errorf("read error: %v", err)
		}

		for _, sym := range obj.Syms {
			allSyms[sym.Name] = symFile{
				sym:  sym,
				file: f,
			}
		}
		goObjs = append(goObjs, obj)
	}

	for i, obj := range goObjs {
		for _, sym := range obj.Syms {
			if sym.Kind == STEXT {
				relocSym(&reloc, symFile{sym: sym,
					file: fs[i]}, allSyms, symMap,
					gcObjs, fileTabOffsetMap)
			}
		}
	}

	return &reloc, nil
}

// relocSym 重定位块
func relocSym(reloc *CodeReloc, curSym symFile,
	allSyms map[string]symFile, symMap map[string]int,
	gcObjs map[string]uintptr, fileTabOffsetMap map[string]int) int {

	if curSymOffset, ok := symMap[curSym.sym.Name]; ok {
		return curSymOffset
	}

	var rsym SymData
	rsym.Name = curSym.sym.Name
	rsym.Kind = int(curSym.sym.Kind)
	curSymOffset := addSym(symMap, &reloc.Syms, &rsym)

	code := make([]byte, curSym.sym.Data.Size)
	curSym.file.Seek(curSym.sym.Data.Offset, io.SeekStart)
	_, err := curSym.file.Read(code)
	mustOK(err)
	switch int(curSym.sym.Kind) {
	case STEXT:
		rsym.Offset = len(reloc.Code)
		reloc.Code = append(reloc.Code, code...)
		readFuncData(&reloc.Mod, curSym, allSyms, gcObjs,
			fileTabOffsetMap, curSymOffset, rsym.Offset)
	default:
		rsym.Offset = len(reloc.Data)
		reloc.Data = append(reloc.Data, code...)
	}
	addSym(symMap, &reloc.Syms, &rsym)

	for _, re := range curSym.sym.Reloc {
		symOff := -1
		if s, ok := allSyms[re.Sym.Name]; ok {
			symOff = relocSym(reloc, s, allSyms, symMap,
				gcObjs, fileTabOffsetMap)
		} else {
			var exSym SymData
			exSym.Name = re.Sym.Name
			exSym.Offset = -1
			if re.Type == R_TLS_LE {
				exSym.Name = TLSNAME
				exSym.Offset = int(re.Offset)
			}
			if re.Type == R_CALLIND {
				exSym.Offset = 0
				exSym.Name = R_CALLIND_NAME
			}
			if strings.HasPrefix(exSym.Name, "type..importpath.") {
				path := strings.TrimLeft(exSym.Name, "type..importpath.")
				path = strings.Trim(path, ".")
				pathb := []byte(path)
				pathb = append(pathb, 0)
				exSym.Offset = len(reloc.Data)
				reloc.Data = append(reloc.Data, pathb...)
			}
			symOff = addSym(symMap, &reloc.Syms, &exSym)
		}
		rsym.Reloc = append(rsym.Reloc,
			Reloc{Offset: int(re.Offset) + rsym.Offset, SymOff: symOff,
				Type: int(re.Type),
				Size: int(re.Size), Add: int(re.Add)})
	}
	reloc.Syms[curSymOffset].Reloc = rsym.Reloc

	return curSymOffset
}

// addSym 添加块
// - 对symArray添加rsym为目标的符号,并增加到symMap列表内.
func addSym(symMap map[string]int, symArray *[]SymData, rsym *SymData) int {
	var offset int
	if of, ok := symMap[rsym.Name]; !ok {
		offset = len(*symArray)
		*symArray = append(*symArray, *rsym)
		symMap[rsym.Name] = offset
	} else {
		offset = of
		(*symArray)[offset] = *rsym
	}
	return offset
}

// DataSym 构建表结构
type DataSym struct {
	Sym     []int           // 用于替换表索引
	Type    map[string]*int // 类型索引
	Itab    []int           // itab索引
	ItabSym map[string]int  // 还原导入
}

// DataBase 模块基址
type DataBase struct {
	Byte     []byte //+ 代码数据
	Len      int    //+ 使用
	Cap      int    //+ 占用
	Base     int    //+ 基址
	DataBase int    //+ 数据基址
	jmpOff   int    // 偏移
}

// Load 对已经加载的静态库进行初始化
// + code   加载函数返回
// + symPtr 符号列表
func Load(code *CodeReloc, symPtr map[string]uintptr) (*CodeModule, error) {
	var err error
	//+ 构建基址信息
	Base := DataBase{}
	Base.Len = len(code.Code) + len(code.Data)
	Base.Cap = int(float32(Base.Len) * 1.5)
	Base.Byte, err = mmap.Mmap(Base.Cap)
	if err != nil {
		return nil, err
	}
	Base.jmpOff = Base.Len
	// 基址信息
	Base.Base = int((*sliceHeader)(unsafe.Pointer(&Base.Byte)).Data)
	Base.DataBase = Base.Base + len(code.Code)

	//+ 构建表结构
	Sym := DataSym{
		Sym:     make([]int, len(code.Syms)),
		Type:    make(map[string]*int),
		ItabSym: make(map[string]int),
	}
	// 构建插件类型
	var Module = CodeModule{
		Syms:    make(map[string]uintptr),
		typemap: make(map[typeOff]uintptr),
	}

	//+ 处理构建表
	if err := symSyms(code, Base, Sym, Module, symPtr); err != nil {
		return nil, err
	}

	//+ 还原 itab 表
	symItab(code, Base, Sym, Module, symPtr)

	//+ 还原重定义块
	if err := restoreSyms(code, Base, Sym, Module, symPtr); err != nil {
		return nil, err
	}

	//+ 构建最终模块
	var Data moduledata
	// 函数信息
	Data.ftab = make([]functab, len(code.Mod.ftab))
	copy(Data.ftab, code.Mod.ftab)
	pclnOff := len(code.Mod.pclntable)
	Data.pclntable = make([]byte, len(code.Mod.pclntable)+(_funcSize+100)*len(code.Mod.ftab))
	copy(Data.pclntable, code.Mod.pclntable)
	// 模块信息
	Data.findfunctab = (uintptr)(unsafe.Pointer(&code.Mod.pcfunc[0]))
	Data.minpc = (uintptr)(unsafe.Pointer(&Base.Byte[0]))                    // 代码起始地址
	Data.maxpc = (uintptr)(unsafe.Pointer(&Base.Byte[len(code.Code)-1])) + 2 // 代码结束地址
	Data.filetab = code.Mod.filetab
	Data.typemap = Module.typemap
	Data.types = uintptr(Base.Base)
	Data.etypes = uintptr(Base.Base + Base.Cap)
	Data.text = uintptr(Base.Base)
	Data.etext = uintptr(Base.DataBase)
	Module.pcfuncdata = code.Mod.pcfunc // hold reference
	Module.stkmaps = code.Mod.stkmaps

	//+ 修复运行偏移
	for i := range Data.ftab {
		if i == 0 {
			continue
		}
		Data.ftab[i].entry = uintptr(Sym.Sym[int(code.Mod.ftab[i].entry)])
		ptr2 := (uintptr)(unsafe.Pointer(&Data.pclntable[pclnOff]))
		if PtrSize == 8 && ptr2&4 != 0 {
			pclnOff += 4
		}
		Data.ftab[i].funcoff = uintptr(pclnOff)
		fi := code.Mod.funcinfo[i-1]
		fi.entry = Data.ftab[i].entry
		copy2Slice(Data.pclntable[pclnOff:],
			unsafe.Pointer(&fi._func), _funcSize)
		pclnOff += _funcSize
		if len(fi.pcdata) > 0 {
			size := int(4 * fi.npcdata)
			copy2Slice(Data.pclntable[pclnOff:],
				unsafe.Pointer(&fi.pcdata[0]), size)
			pclnOff += size
		}
		var funcdata = make([]uintptr, len(fi.funcdata))
		copy(funcdata, fi.funcdata)
		for i, v := range funcdata {
			funcdata[i] = (uintptr)(unsafe.Pointer(&(code.Mod.stkmaps[v][0])))
		}
		ptr := (uintptr)(unsafe.Pointer(&Data.pclntable[pclnOff-1])) + 1
		if PtrSize == 8 && ptr&4 != 0 {
			t := [4]byte{}
			copy(Data.pclntable[pclnOff:], t[:])
			pclnOff += len(t)
		}
		funcDataSize := int(PtrSize * fi.nfuncdata)
		copy2Slice(Data.pclntable[pclnOff:],
			unsafe.Pointer(&funcdata[0]), funcDataSize)
		pclnOff += funcDataSize
	}

	//+ 修复绑定异常
	Data.pclntable = Data.pclntable[:pclnOff]
	if len(Data.ftab) >= 2 {
		Data.ftab[0] = Data.ftab[1]
	}

	modulesLock.Lock()
	addModule(&Module, &Data, runtime.Version())
	modulesLock.Unlock()

	copy(Base.Byte, code.Code)
	copy(Base.Byte[len(code.Code):], code.Data)
	Module.CodeByte = Base.Byte

	//+ 修复 itabSyms
	for i := range Module.itabSyms {
		it := &Module.itabSyms[i]
		if it.inter == -1 || it._type == -1 {
			continue
		}
		it.ptr = getitab(it.inter, it._type, false)
	}

	//+ 修复 itabs
	for _, it := range Module.itabs {
		symAddr := Module.itabSyms[it.symOff].ptr
		if symAddr == 0 {
			continue
		}
		switch it.locType {
		case R_PCREL:
			pc := Base.Base + it.locOff + it.size
			offset := symAddr - pc + it.add
			if offset > 2147483647 || offset < -2147483647 {
				offset = (Base.Base + Base.jmpOff) - pc + it.add
				binary.LittleEndian.PutUint32(Base.Byte[it.locOff:], uint32(offset))
				Base.Byte[it.locOff-2:][0] = movcode
				*(*uintptr)(unsafe.Pointer(&(Base.Byte[Base.jmpOff:][0]))) = uintptr(symAddr)
				Base.jmpOff += PtrSize
				continue
			}
			binary.LittleEndian.PutUint32(Base.Byte[it.locOff:], uint32(offset))
		case R_ADDRARM64:
			relocADRP(Base.Byte[it.locOff:], Base.Base+it.locOff, symAddr, "unknown")
		}
	}

	return &Module, nil
}

// symSyms 处理符号表
func symSyms(code *CodeReloc, Base DataBase, Sym DataSym, Module CodeModule, symPtr map[string]uintptr) error {
	// 处理错误
	var errBuf bytes.Buffer
	// 递归导出表
	for i, sym := range code.Syms {
		//+ 偏移为-1代表为外部引用
		if sym.Offset == -1 {
			//+ 判断是否存在替换符号地址
			if ptr, ok := symPtr[sym.Name]; ok {
				Sym.Sym[i] = int(ptr) //+ 替换为外部指针
				continue
			}
			//+ 判断是否有其他替换方案
			if ptr, ok := symPtr[sym.Name+"-fm"]; ok {
				Sym.Sym[i] = int(ptr) //+ 替换为外部指针
				continue
			}
			//+ 判断是否为浮点数
			if sym.Name[0] == '$' && len(sym.Name) > 5 {
				Sym.Sym[i] = -2
				continue
			}
			//+ 无法得到符号实现
			Sym.Sym[i] = -1
			strWrite(&errBuf, "符号为外部调用但没有实现:", sym.Name, "\n")
			continue // 直接跳过其他处理
		}
		//+ 调度用的内部标记
		//   用于存储 g 地址的列表
		if sym.Name == TLSNAME {
			RegTLS(symPtr, sym.Offset)
			continue
		}
		//+ 可执行命令
		// 记录函数入口地址
		if sym.Kind == STEXT {
			Sym.Sym[i] = code.Syms[i].Offset + Base.Base
			Module.Syms[sym.Name] = uintptr(Sym.Sym[i])
			continue
		}
		//+ 接口/数据类型
		// itab 存放类型及方法指针信息
		if strings.HasPrefix(sym.Name, "go.itab") {
			if ptr, ok := symPtr[sym.Name]; ok {
				Sym.Sym[i] = int(ptr)
			} else {
				Sym.Itab = append(Sym.Itab, i)
			}
			continue
		}
		//+ 其他构建处理
		// 处理偏移
		Sym.Sym[i] = code.Syms[i].Offset + Base.DataBase
		//+ 处理函数类型
		if strings.HasPrefix(sym.Name, "type.func") {
			Sym.Type[sym.Name] = &Sym.Sym[i]
			continue
		}
		//+ 处理结构体类型
		if strings.HasPrefix(sym.Name, "type.") {
			if ptr, ok := symPtr[sym.Name]; ok {
				Sym.Sym[i] = int(ptr)
				continue
			}
		}
	}
	// 输出错误
	if errBuf.Len() > 0 {
		return errors.New(errBuf.String())
	}
	return nil
}

// symItab 处理类型表
func symItab(code *CodeReloc, Base DataBase, Sym DataSym, Module CodeModule, symPtr map[string]uintptr) {
	for _, itabIndex := range Sym.Itab {
		curSym := code.Syms[itabIndex]
		//+ 处理结构
		sym1 := Sym.Sym[curSym.Reloc[0].SymOff] // 接口自身的静态类型
		sym2 := Sym.Sym[curSym.Reloc[1].SymOff] // 接口存放的具体实例的类型（动态类型）
		// 构建
		Sym.ItabSym[curSym.Name] = len(Module.itabSyms)
		Module.itabSyms = append(Module.itabSyms, itabSym{inter: sym1, _type: sym2})
		if sym1 == -1 || sym2 == -1 {
			continue
		}
		addIFaceSubFuncType(Sym.Type, Module.typemap, (*interfacetype)(unsafe.Pointer(uintptr(sym1))), Base.Base)
	}
}

// restoreSyms 还原重定义块
func restoreSyms(code *CodeReloc, Base DataBase, Sym DataSym, Module CodeModule, symPtr map[string]uintptr) error {
	// 处理错误
	var errBuf bytes.Buffer
	var err error
	for _, curSym := range code.Syms {
		for _, loc := range curSym.Reloc {
			//+ 跳过处理
			if Sym.Sym[loc.SymOff] == -1 {
				continue
			}
			//+ 处理 itab
			sym := code.Syms[loc.SymOff]
			if Sym.Sym[loc.SymOff] == 0 && strings.HasPrefix(sym.Name, "go.itab") {
				Module.itabs = append(Module.itabs,
					itabReloc{locOff: loc.Offset, symOff: Sym.ItabSym[sym.Name],
						size: loc.Size, locType: loc.Type, add: loc.Add})
				continue
			}
			err = restoreReloc(code, Base, Sym, loc, curSym, symPtr)
			if err != nil {
				strWrite(&errBuf, err.Error(), "\n")
			}
		}
	}
	// 输出错误
	if errBuf.Len() > 0 {
		return errors.New(errBuf.String())
	}
	return nil
}

// 还原代码块符号
//+ 替换指令字节集
var (
	armcode        = []byte{0x04, 0xF0, 0x1F, 0xE5, 0x00, 0x00, 0x00, 0x00}
	arm64code      = []byte{0x43, 0x00, 0x00, 0x58, 0x60, 0x00, 0x1F, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
	x86code        = []byte{0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
	movcode   byte = 0x8b
	leacode   byte = 0x8d
)

// restoreReloc 还原重定义块
func restoreReloc(code *CodeReloc, Base DataBase, Sym DataSym, loc Reloc, curSym SymData, symPtr map[string]uintptr) error {
	var offset int
	//+ R_TLS_LE 线程相关处理
	if loc.Type == R_TLS_LE {
		binary.LittleEndian.PutUint32(code.Code[loc.Offset:], uint32(symPtr[TLSNAME]))
		return nil
	}
	// 符号信息
	sym := code.Syms[loc.SymOff]

	//+ 初始化代码偏移信息
	var relocByte = code.Data
	var addrBase = Base.DataBase
	// 判断是否为代码区偏移
	if curSym.Kind == STEXT {
		// 以代码起始地址进行偏移
		addrBase = Base.Base
		relocByte = code.Code
	}

	//+ R_CALL与R_PCREL
	if loc.Type == R_CALL || loc.Type == R_PCREL {
		//+ 未知数据类型
		if sym.Kind == Sxxx {
			//+ 相对地址
			offset = (Base.Base + Base.jmpOff) - (addrBase + loc.Offset + loc.Size)
			if Sym.Sym[loc.SymOff] == -2 {
				// 处理数据
				x, err := strconv.ParseUint(sym.Name[5:], 16, 64)
				if err != nil {
					return errors.New(fmt.Sprintf("解析浮点数符号失败 %s: %v", sym.Name, err))
				}
				// 写入数据
				switch sym.Name[:5] {
				case "$f32.":
					if uint64(uint32(x)) != x {
						return errors.New(fmt.Sprintf("解析浮点数符号失败 %s: %v", sym.Name, err))
					}
					binary.LittleEndian.PutUint32(Base.Byte[Base.jmpOff:], uint32(x))
					Base.jmpOff += 8
				case "$f64.":
					binary.LittleEndian.PutUint64(Base.Byte[Base.jmpOff:], uint64(x))
					Base.jmpOff += 16
				default:
					return errors.New(fmt.Sprintf("未知浮点数类型: %s", sym.Name))
				}
				// 写入地址
				binary.LittleEndian.PutUint32(code.Code[loc.Offset:], uint32(offset))
				return nil
			}
		}

		//+ 判断溢出
		//+ 判断是否为相对地址
		offset = Sym.Sym[loc.SymOff] - (addrBase + loc.Offset + loc.Size) + loc.Add
		if offset > 0x7fffffff || offset < -0x7fffffff {
			if Base.jmpOff+8 > Base.Cap {
				return errors.New("跳转地址溢出: " + sym.Name + "\n")
			}
		} else {
			binary.LittleEndian.PutUint32(relocByte[loc.Offset:], uint32(offset))
			return nil
		}

		//+ 相对地址
		offset = (Base.Base + Base.jmpOff) - (addrBase + loc.Offset + loc.Size)
		//+ SNOPTRBSS 静态数据未初始化的
		if sym.Kind == SNOPTRBSS {
			if loc.Size == 8 {
				binary.LittleEndian.PutUint64(relocByte[loc.Offset:], uint64(offset))
			} else if loc.Size == 4 {
				binary.LittleEndian.PutUint32(relocByte[loc.Offset:], uint32(offset))
			} else {
				return errors.New("异常指令范围: " + sym.Name + "\n")
			}
			//+ 计算参数占用大小
			for _, rloc := range sym.Reloc {
				Base.jmpOff += rloc.Size
			}
			return nil
		}

		//+ SRODATA 只读静态数据
		if sym.Kind == SRODATA {
			rb := relocByte[loc.Offset-2:]
			if rb[0] == leacode || rb[0] == movcode {
				binary.LittleEndian.PutUint32(relocByte[loc.Offset:], uint32(offset))
				rb[0] = movcode
				binary.LittleEndian.PutUint32(Base.Byte[Base.jmpOff:], uint32(Sym.Sym[loc.SymOff]+loc.Add))
				Base.jmpOff += 8
				return nil
			}
		}

		//+ 解析错误
		return errors.New(fmt.Sprintf("未知解析类型: %#v", sym))
	}

	//+ 其他调用处理
	if loc.Type == R_CALLARM || loc.Type == R_CALLARM64 {
		var add = loc.Add
		var pcOff = 0
		if loc.Type == R_CALLARM {
			add = loc.Add & 0xffffff
			if add > 256 {
				add = 0
			} else {
				add += 2
			}
			pcOff = 8
		}
		offset = (Sym.Sym[loc.SymOff] - (Base.Base + loc.Offset + pcOff) + add) / 4
		if offset > 0x7fffff || offset < -0x7fffff {
			if Base.jmpOff+4 > Base.Cap {
				return errors.New("跳转地址溢出: " + sym.Name + "\n")
			}
			align := Base.jmpOff % 4
			if align != 0 {
				Base.jmpOff += (4 - align)
			}
			offset = (Base.jmpOff - (loc.Offset + pcOff)) / 4
			var v = uint32(offset)
			b := code.Code[loc.Offset:]
			b[0] = byte(v)
			b[1] = byte(v >> 8)
			b[2] = byte(v >> 16)
			var jmpLocOff = 0
			var jmpLen = 0
			if loc.Type == R_CALLARM64 {
				copy(Base.Byte[Base.jmpOff:], arm64code)
				jmpLen = len(arm64code)
				jmpLocOff = 8
			} else {
				copy(Base.Byte[Base.jmpOff:], armcode)
				jmpLen = len(armcode)
				jmpLocOff = 4
			}
			*(*uintptr)(unsafe.Pointer(&(Base.Byte[Base.jmpOff+jmpLocOff:][0]))) = uintptr(Sym.Sym[loc.SymOff] + add*4)
			Base.jmpOff += jmpLen
			return nil
		}
		var v = uint32(offset)
		b := code.Code[loc.Offset:]
		b[0] = byte(v)
		b[1] = byte(v >> 8)
		b[2] = byte(v >> 16)
		return nil
	}
	//+ R_ADDRARM64 处理
	if loc.Type == R_ADDRARM64 {
		if curSym.Kind != STEXT {
			return errors.New("代码解析为空: " + sym.Name + "\n")
		}
		relocADRP(code.Code[loc.Offset:], Base.Base+loc.Offset, Sym.Sym[loc.SymOff], sym.Name)
		return nil
	}

	//+ R_ADDR 处理
	if loc.Type == R_ADDR {
		offset = Sym.Sym[loc.SymOff] + loc.Add
		*(*uintptr)(unsafe.Pointer(&(relocByte[loc.Offset:][0]))) = uintptr(offset)
		return nil
	}

	//+ 其他处理
	if loc.Type == R_ADDROFF || loc.Type == R_WEAKADDROFF || loc.Type == R_METHODOFF {
		var relocByte = code.Data
		var addrBase = Base.Base
		if curSym.Kind == STEXT {
			return errors.New("解析失败无法定位代码信息:" + sym.Name + "\n")
		}
		offset = Sym.Sym[loc.SymOff] - addrBase + loc.Add
		binary.LittleEndian.PutUint32(relocByte[loc.Offset:], uint32(offset))
		return nil
	}
	//+ 输出错误
	return errors.New("未知解析类型: " + strconv.Itoa(loc.Type) + "  " + sym.Name + "\n")
}

func strWrite(buf *bytes.Buffer, str ...string) {
	for _, s := range str {
		buf.WriteString(s)
		if s != "\n" {
			buf.WriteString(" ")
		}
	}
}

func relocADRP(mCode []byte, pc int, symAddr int, symName string) {
	pcPage := pc - pc&0xfff
	lowOff := symAddr & 0xfff
	symPage := symAddr - lowOff
	pageOff := symPage - pcPage
	if pageOff > 1<<31 || pageOff < -1<<31 {
		movlow := binary.LittleEndian.Uint32(mov32bit[:4])
		movhigh := binary.LittleEndian.Uint32(mov32bit[4:])
		adrp := binary.LittleEndian.Uint32(mCode)
		symAddrUint32 := uint32(symAddr)
		movlow = (((adrp & 0x1f) | movlow) | ((symAddrUint32 & 0xffff) << 5))
		movhigh = (((adrp & 0x1f) | movhigh) | ((symAddrUint32 & 0xffff0000) >> 16 << 5))
		binary.LittleEndian.PutUint32(mCode, movlow)
		binary.LittleEndian.PutUint32(mCode[4:], movhigh)
		return
	}
	pageAnd := (uint32((pageOff>>12)&3) << 29) | (uint32((pageOff>>15)&0x7ffff) << 5)

	adrp := binary.LittleEndian.Uint32(mCode)
	adrp = adrp | pageAnd
	binary.LittleEndian.PutUint32(mCode, adrp)

	lowOff = lowOff << 10
	adrpAdd := binary.LittleEndian.Uint32(mCode[4:])
	adrpAdd = adrpAdd | uint32(lowOff)
	binary.LittleEndian.PutUint32(mCode[4:], adrpAdd)
}

func copy2Slice(dst []byte, src unsafe.Pointer, size int) {
	var s = sliceHeader{
		Data: (uintptr)(src),
		Len:  size,
		Cap:  size,
	}
	copy(dst, *(*[]byte)(unsafe.Pointer(&s)))
}
